package org.pupil.router.ConsistentHash;

import org.pupil.common.URL;
import org.pupil.router.LoadBalancer;
import org.pupil.router.LoadContext;
import org.pupil.utils.IPBuilder;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * @Description: 负载均衡：一致性哈希环
 * @Author: pupil
 * @Date: 2024/07/24 下午 3:15
 */
public class ConsistentHashLoadBalancer implements LoadBalancer {

    // 物理节点映射的虚拟节点,为了解决哈希倾斜
    private final static int VIRTUAL_NODE_SIZE = 10;  //虚拟节点大小
    private final static String VIRTUAL_NODE_SPLIT = "$"; //虚拟节点拆分

    @Override
    public URL select(LoadContext loadContext) {
        List<URL> urls = loadContext.getUrls();
        Object parameter = loadContext.getParameter();
        return allocateNode(makeConsistentHashRing(urls),parameter.hashCode());
    }

    /**
     * 获取当前服务节点
     *
     * @param ring     一致性哈希环
     * @param hashCode 参数的哈希值
     * @return 当前服务节点
     */
    private URL allocateNode(TreeMap<Integer, URL> ring, int hashCode) {
        // 获取最近的哈希环上节点位置
        Map.Entry<Integer, URL> entry = ring.ceilingEntry(hashCode);
        if (entry == null) {
            // 如果没有找到则使用最小的节点
            entry = ring.firstEntry();
        }
        return entry.getValue();
    }


    /**
     * 将所有服务实例添加到一致性哈希环上，并生成虚拟节点
     * 这里每次调用都需要构建哈希环是为了扩展(服务提供方)
     * @param urls
     * @return
     */
    private TreeMap<Integer, URL> makeConsistentHashRing(List<URL> urls) {
        //利用TreeMap底层是红黑树的特性来实现致性哈希环,自动排序
        TreeMap<Integer, URL> ring = new TreeMap<>();
        for (URL url : urls) {
            for (int i = 0; i < VIRTUAL_NODE_SIZE; i++) {
                ring.put((IPBuilder.buildIp(url.getIP(),url.getPort()) + VIRTUAL_NODE_SPLIT + i).hashCode(), url);
            }
        }
        return ring;
    }


}
